<?php
  // shardStatus class
  // This is the meat and potatoes of the mod_getRiftShardStatus module.
  // In object-oriented programming, you create re-usable blocks of code
  // (i.e. classes) along with interfaces to that code.
  //
  // With writing this module using the class paradigm, technically we
  // now have the flexibility of making interface code in all kinds of
  // other places.  We could put it in a regular non-Joomla site, or another
  // content management system entirely, without changing a single piece of
  // code.  And all the code you need for the "interface" page, is:
  //
  // echo shardStatus::showJoomlaModule($params);
  // The 'echo' keyword in PHP does the same thing as 'write' did for Pascal,
  // and in that line above we are referencing the "showJoomlaModule()"
  // method of the "shardStatus" class, and passing the variable "$params"
  // to it.
  //
  // There is nothing specific to Joomla at all in this module (other than
  // the function name I gave that output function).  I put all the
  // Joomla-specific code in the interface pages (default.php and
  // mod_getRiftShardStatus.php)

  // While the class design is not particularly useful in this situation
  // because this code and the module are so very specific in their
  // utility that I doubt I''ll ever use this code again for anything else,
  // I find its always a good practice to code with object-oriented
  // methodology in mind. After you get used to the way it works, I think
  // it actually makes code a lot easier to read and troubleshoot.

class shardStatus
{
	// loadShardStatusXMLFeed
	// This function is used to read the Trion XML feed into memory
	//
	// Returns: a reference to memory where the contents of
	//          the XML file were stored
	function loadShardStatusXMLFeed($xmlFeedURL)
	{
		$url=$xmlFeedURL;  // taking advantage of Joomla module params

		// Use PHP5s built-in xml reader to load the contents
		// of the entire XML file into memory, specifically into the
		// variable called $xml.
		//
		// If there is a problem doing so, spawn a PHP Error event that
		// kills the browser session with this app.
		//
		if(!$xml=simplexml_load_file($url)){
		  trigger_error("Error reading XML file",E_USER_ERROR);
		}
		return $xml;
	}

	// isValidShardName
	// Tests whether the provided shard name is valid or not
	// (basically just if it is in the XML feed)
	//
	// Returns: true or false
	function isValidShardName($xml, $shardName)
	{
	  $shardFound=false;   // set the initial return variable to false
	                       // this is more a personal preference than
	                       // a best-practice.  I always set boolean
	                       // to false first, and have a qualifying
	                       // condition set it to true...that way
	                       // there is always a value in the variable
	                       // AND if there is any problem with either my
	                       // program logic or the conditions I am testing
	                       // themselves, they will be much more apparently
	                       // and easier to track this way.

	  // Cycle through all of the lines of the XML feed; essentially foreach
	  // takes each line of the XML and sticks it into a new variable array
	  // named $shard
	  foreach($xml as $shard){
		$shardInfo=$shard->attributes();  // stick all of the attributes of the
		                                  // XML element into an array.  The
		                                  // attributes() method essentially takes
		                                  // all of the XML attributes that are
		                                  // currently found in the $shard variable
		                                  // and sticks them into the new $shardInfo
		                                  // array
		// This part compares the current shard name from the XML feed, to the
		// one provided by the variable (and by proxy, via the Joomla Module Manager).
		// NOTE: For text comparisons, I always make sure to
		//       compare strings on an even playing field.
		//       In this case, I've made both the shard name
		//       from XML ($shardInfo["name"]) and the one
		//       provided via Joomla ($shardName) ALL CAPS
		//       by using the strtoupper() function and also
		//       trimmed off any leading or trailing whitespace
		//       characters using trim().
		if(strtoupper(trim($shardInfo["name"]))==strtoupper($shardName))
		  $shardFound=true;
	  }
	  return $shardFound;
	}

    // isShardOnline
    // This function tests if the shard is online by checking the current
    // value of the "online" attribute from the XML feed for the given shard
    //
    // Returns: true or false
	function isShardOnline($xml, $shardName)
	{
	  // In this function, I didn't initialize or use a variable to
	  // say whether the shard online was true or false.  This is because
	  // I am using this function like a giant variable.  The function
	  // itself returns a value of true or false.  This is just another one
	  // of those personal preference things that I've adopted over the years.
	  if(shardStatus::isValidShardName($xml,$shardName)){
		  foreach($xml as $shard){
			$shardInfo=$shard->attributes();
			if(strtoupper(trim($shardInfo["name"]))==strtoupper($shardName)) {
			  $shardFound=true;
			  $shardStatus=trim($shardInfo["online"]);
			  if($shardStatus=="True") {
				return true;
			  } else { return false; }
			}
		  }
	  } else {
		echo "A North American Rift shard with the name <b>".strtoupper(trim($shardName))."</b> could not be found in the XML data.  Please check your URL.<br>";
	  }
	}

    // isShardLocked
    // This function tests if the shard is locked by checking the current
    // value of the "locked" attribute from the XML feed for the given shard
    //
    // Returns: true or false
	function isShardLocked($xml, $shardName)
	{
	  if(shardStatus::isValidShardName($xml,$shardName)){
		  foreach($xml as $shard){
			$shardInfo=$shard->attributes();
			if(strtoupper(trim($shardInfo["name"]))==strtoupper($shardName)) {
			  $shardFound=true;
			  $shardStatus=trim($shardInfo["locked"]);
			  if($shardStatus=="True") {
				return true;
			  } else { return false; }
			}
		  }
	  } else {
		echo "A North American Rift shard with the name <b>".strtoupper(trim($shardName))."</b> could not be found in the XML data.  Please check your URL.<br>";
	  }
	}

    // getShardQueue
    // Gets the current length of the queue for the given shard, using
    // the "queued" attribute from the XML feed
    //
    // Returns: the length of the queue ("0" if no queue, or whatever the queue length is if there is one)
	function getShardQueue($xml, $shardName)
	{
	  if(shardStatus::isValidShardName($xml,$shardName)){
		  foreach($xml as $shard){
			$shardInfo=$shard->attributes();
			if(strtoupper(trim($shardInfo["name"]))==strtoupper($shardName)) {
			  $shardFound=true;
			  return trim($shardInfo["queued"]);
			}
		  }
	  } else {
		echo "A North American Rift shard with the name <b>".strtoupper(trim($shardName))."</b> could not be found in the XML data.  Please check your URL.<br>";
	  }
	}

	function calculateQueueTime($queueLength)
	{
	  // Based on my experience in tonight (3/19)'s queue, the Rift formula for calculating time
	  // is approximately 5-15 seconds per current queue length.  To simulate this
	  // same feature, we will do roughly the same (only calculating based on 10 seconds for ease
	  // of my anger towards the math gods)

	  $queueTime=abs(round((($queueLength*10)/60)));  // the magic:
	                                                  // The absolute value of $queueLength
	                                                  // multiplied by 10 (seconds), then divided
	                                                  // by 60 (to get minutes), then the result
	                                                  // is rounded to the nearest full integer.
	  if($queueTime<1)
	    $queueTime=1;  // Never display "About 0 minutes", that's dumb.

	  // Now that we have our queueTime in minutes, lets make that a little more readable:
	  $hours=floor($queueTime/60);
	  $minutes=$queueTime % 60;  // The remainder (modulus) of (minutes/60) is the minutes

	  $queueTimeOutput="About";
	  if($hours>0){
	    if($hours>1){                                              // if more than one hour, say "hours"
	                                                               // (and likewise for "minute"(s))
	      $queueTimeOutput=$queueTimeOutput." ".$hours." hours";
	      if($minutes>1){
	        $queueTimeOutput=$queueTimeOutput." and ".$minutes." minutes.";
	      } else {
	        $queueTimeOutput=$queueTimeOutput." and ".$minutes." minute.";
		  }
	    } else {                                                   // single hour and some minutes
	      $queueTimeOutput=$queueTimeOutput." ".$hours." hour";
	      if($minutes>1){
	        $queueTimeOutput=$queueTimeOutput." and ".$minutes." minutes.";
	      } else {
	        $queueTimeOutput=$queueTimeOutput." and ".$minutes." minute.";
		  }
		}
	  } else {                                                    // if we're just talking about minutes
	    if($minutes>1){
	      $queueTimeOutput=$queueTimeOutput." ".$minutes." minutes.";
	    } else {
	      $queueTimeOutput=$queueTimeOutput." ".$minutes." minute.";
	    }
	  }

	  return $queueTimeOutput;
	}

    // showJoomlaModule
    // Essentially the function that brings all of the application logic together and
    // forms the output and interface with the user
    //
    // Returns: variable with complete output stored inside it
    // Example Usage:
    //         $output=shardStatus::showJoomlaModule($params);
    //         echo $output;
    //     OR
    //         echo shardStatus::showJoomlaModule($params);

	function showJoomlaModule($params)
	{

	  // Import Joomla Module Manager module preference variables
	  //
	  // Get the parameters out of Joomla Module Manager
	  // and assign them to local variable:
	  // $variableName=$params->get('parameter_name_from_xml_file');
	  //
	  $shardName=$params->get('shard');
	  $xmlFeedURL=$params->get('xmlFeedURL');
	  $xml=shardStatus::loadShardStatusXMLFeed($xmlFeedURL);
	  $successColor=$params->get('successColor');
	  $failColor=$params->get('failColor');
	  // End of Joomla Module Manager parameters


	  $shardOnline=false;
	  $queueLength="0";  // Set the initial queue length to 0.  If there is an actual queue,
	                     // obviously this value will be replaced, but it gives us
	                     // something to work with

	  $output="";        // Initialize the $output variable as an empty string so we start
	                     // the output with a clean slate
	  if(shardStatus::isValidShardName($xml,$shardName)){
		$output="<center><table>";
		$output=$output."<tr><td align='center' colspan='2'><font size='+1'><b>".$shardName." Status</b></font></td></tr>";
		$output=$output."<tr><td align='center' colspan='2'><hr></td></tr>";
		$output=$output."<tr><td align='right'><font size='+1'><b>Server:</b></font></td>";

		// Make sure the shard is online before we go crazy on processing
		if(shardStatus::isShardOnline($xml,$shardName)){
		  $shardOnline=true;
		  // Make sure the shard isn't locked before we check for queues
		  if(shardStatus::isShardLocked($xml,$shardName)){
			$output=$output."<td align='left'><font color='".$failColor."' size='+1'><b>LOCKED</b></font></td>";
		  } else {
			// since now we know the shard is online, go ahead and check the queue
			$queueLength=shardStatus::getShardQueue($xml,$shardName);

			// if the value of $queueLength isn't "0", it has a queue and should be displayed as FULL
			// differently
			if($queueLength!="0"){
			  $output=$output."<td align='left'><font color='".$failColor."' size='+1'><b>FULL</b></font></td>";
			} else {
			  $output=$output."<td align='left'><font color='".$successColor."' size='+1'><b>ONLINE</b></font></td>";
			}
		  }
		} else {
		  $output=$output."<td align='left'><font color='".$failColor."' size='+1'><b>OFFLINE</b></font></td>";
		}
		$output=$output."</tr>";

		// Now display the 2nd row of output ("NO WAIT" or "Queue: ###")
		if($shardOnline){
			if($queueLength!="0"){
			  $output=$output."<tr><td align='right'><font size='+1'><b>Queue:</b></font></td><td align='left'><font color='".$failColor."' size='+1'><b>".$queueLength."</b></font></td></tr>";
			  $output=$output."<tr><td align='center' colspan='2'><font size='-1' color='".$failColor."'><b>".shardStatus::calculateQueueTime($queueLength)."</b></font></td></tr>";
			} else {
			  $output=$output."<tr><td align='center' colspan='2'><font color='".$successColor."' size='+1'><b>NO WAIT</b></font></td></tr>";
			}
		} else {
		  $output=$output."<tr><td align='center' colspan='2'><font color='".$failColor."' size='+1'><b>NO STATUS</b></font></td></tr>";
		}
		$output=$output."</table></center>";
      } else {
        // If the name of the shard that was specified in the Joomla Module Manager
        // can't be found in the Trion XML feed, let the user know
        $output=$output."<center><font color='".$failColor."' size='+1'><b>INVALID SHARD NAME</b></font></center>";
      }

      return $output;  // send the output to the calling page
                       // the data that is now in this variable is the entire output that is
                       // seen in Joomla
	}
}

?>